#ifndef H_PARTICLE
#define H_PARTICLE

#include "vector.h"
#include "debug.h"
#include "animatedDrawable.h"
#include "list.h"
#include <math.h>
#include <stdlib.h>
#include <list>

// This defs are meant to be use to ease the definition
// of particles with similar properties eg:
// UINT massive = PARTIVLE_HAS_MASS;
// UINT charges = PARTICLE_HAS_MASS | PARTICLE_HAS_CHARGE

#define PARTICLE_NO_INTERACTIONS 0x0
#define PARTICLE_IS_SOLID 0x1
#define PARTICLE_HAS_MASS 0x2
#define PARTICLE_HAS_FPS 0x4
#define PARTICLE_IS_UNELASTIC 0x8


//A particle descriprtion is class used to describe all the particles with
//similar properties. For examples all asteroids are solid and have the same
//mass
class ParticleDescription {
   public:
      UINT properties;

      UINT fps;

ParticleDescription  ( UINT _properties  )  {
   pDebug( this << " ParticleDescription (" << "UINT _properties =" << &_properties   << ")")
 	 properties = _properties;
	 fps = 0;
      }

void setFps ( float _fps  )  {
   pDebug( this << " void setFps(" << "float _fps =" << &_fps   << ")")
 	 if (_fps != 0. ) fps = (UINT) floor(1000./_fps); else fps=0;
      }
};

class Constraint;

class Particle  {
   private:
      Drawable* drawable;
      UINT start_ticks;
      std::list<Constraint*>* constraints;

   public:
      ParticleDescription* pd;

Drawable* getDrawable (  )  {
   pDebug( this << " Drawable* getDrawable("   << ")")
 	return drawable;
      }	

      Vector pos;
      Vector vel;
      Vector acc;

      //for particle without sprite
Particle  ( Vector const & _pos, Vector const & _vel, Vector const & _acc    )  {
   pDebug( this << " Particle (" << "Vector const & _pos=" << &_pos << "Vector const & _vel=" << &_vel << "Vector const & _acc =" << &_acc     << ")")
 	 pos = _pos; 
	 vel = _vel; 
	 acc = _acc;
	 start_ticks = 0;
	 drawable = NULL;
	 constraints = new std::list<Constraint*> ();
      }

      //particles with sprite not animated
Particle  ( Vector const & _pos, Vector const & _vel, Vector const & _acc, Sprite * _sprite, ParticleDescription* _pd      )  {
   pDebug( this << " Particle (" << "Vector const & _pos=" << &_pos << "Vector const & _vel=" << &_vel << "Vector const & _acc=" << &_acc << "Sprite * _sprite=" << &_sprite << "ParticleDescription* _pd =" << &_pd       << ")")
 	 pos = _pos; 
	 vel = _vel; 
	 acc = _acc;
	 pd = _pd;
	 start_ticks = 0;
	 constraints = new std::list<Constraint*> ();

	 if ( ! _sprite->animated ) {
	    pDebug ( "Passing a static Sprite" );
	    drawable = new Drawable ( _sprite );
	 } 
	 else {
	    pDebug ( "Passing animated Sprite" );
	    drawable = new AnimatedDrawable( _sprite );
	 }

	 actualizeSprite(0);
      }

void actualizeSprite  ( UINT ticks  )  {
   pDebug( this << " void actualizeSprite (" << "UINT ticks =" << &ticks   << ")")
 	vel.show();

	 drawable->getPosRect()->x =  (int) floor ( pos.getx() );
	 drawable->getPosRect()->y =  (int) floor ( pos.gety() );

	 if ( pd->properties & PARTICLE_HAS_FPS ) {
	    if ( (pd->fps != 0.) && ( ticks - start_ticks > pd->fps ) ){
	       drawable->advance();
	       start_ticks = ticks;
	    }
	 }
     }

virtual void resetAcc (  )  {
   pDebug( this << " virtual void resetAcc("   << ")")
 	vel.show();
	acc.set(0.,0.);
     }

     void addConstraint ( Constraint & );
     void honorConstraints ();
};

class ParticleListNode : public ListNode { //Double linked list
   public:
 ParticleListNode  ( ParticleListNode* _prev, Particle & _part, ParticleListNode* _next    ) :  ListNode ( _prev,(Listable&)_part,_next) {
   pDebug( this << " ParticleListNode (" << "ParticleListNode* _prev=" << &_prev << "Particle & _part=" << &_part << "ParticleListNode* _next =" << &_next     << ")")
       }
};

class ParticleList: public List{
   public:
 ParticleList  (  ) :  List () {
   pDebug( this << " ParticleList ("   << ")")
       }
      void add ( Particle * );
      Particle * iter ();
};

// This is the abstrac class of constraint the first subclass i'll code will be
// the plane constraint

class Constraint: public Listable {
   public:
      virtual void honor ( Particle* ) {}
};

class PlaneConstraint : public Constraint {
   private:
      Vector normal;
      Vector position;
   public:
      PlaneConstraint ( Vector const & _normal, Vector const & _position ) {
	 normal = _normal.versor();
	 position = _position;
      }

      virtual void honor (  Particle* );
};

class PhysicsContext {
   public:
      float width;
      float height;
      float timeResulution;
      Timer* timer;
PhysicsContext  ( const float _width, const float _height, const float _timeResolution, Timer* _timer     )  {
   pDebug( this << " PhysicsContext (" << "const float _width=" << &_width << "const float _height=" << &_height << "const float _timeResolution=" << &_timeResolution << "Timer* _timer =" << &_timer      << ")")
 	 width = _width; 
	 height = _height; 
	 timeResulution = _timeResolution;
	 timer = _timer;
      }

};

typedef void (*fieldAction)(Particle*, PhysicsContext*);

class Field: public Listable {
   public:
Field  ( fieldAction _fap  )  {
   pDebug( this << " Field (" << "fieldAction _fap =" << &_fap   << ")")
 	 fap = _fap;
      }
      fieldAction fap;
};

class ParticleEngine {
   private:
      std::list<Field> fields;
      std::list<Particle> particles;

      DrawableList* drawableList;

      float deltaTime;
      PhysicsContext *pc;
   public:
ParticleEngine  ( PhysicsContext * _pc, DrawableList* _drawableList   )  {
   pDebug( this << " ParticleEngine (" << "PhysicsContext * _pc=" << &_pc << "DrawableList* _drawableList =" << &_drawableList    << ")")
 	 drawableList = _drawableList;
	 pc = _pc; 
      }
      void add ( Particle & );
      void actualize ();
      void addField ( Field & );
      void checkCollisions();
      void applyFields ();
};

//returns 1 if collision 0 otherwise
int checkRectCollision( Rect&, Rect& );

#endif
